interface RangeInfo {
  /**
   * excludeRange 均使用 active 的取反值
   */
  excludeRange: [number, number];
  /**
   * includeRange 均使用 active 的值
   */
  includeRange: [number, number];
  active: "anchor" | "current";
}

type NoneRangeInfo = null;

/**
 * 界定批量选择时范围内元素需要使用的值
 */
class RecordRange {
  /**
   * anchor 一旦设置就不会改变
   */
  anchor: number | null = null;
  /**
   * [rangeStart, rangeEnd)
   */
  range: [number, number] | null = null;
  add(index: number): RangeInfo | NoneRangeInfo {
    if (this.anchor == null) {
      this.anchor = index;
      /** 选框未成立 */
      return null;
    }
    if (this.range == null) {
      if (this.anchor === index) {
        /** 选框未成立 */
        return null;
      }
      const rangeStart = Math.min(this.anchor, index);
      const rangeEnd = Math.max(this.anchor, index) + 1;
      this.range = [rangeStart, rangeEnd];
      /** 选框初始化，使用锚点值 */
      return {
        excludeRange: [-1, -1],
        includeRange: [...this.range],
        active: "anchor",
      };
    } else {
      if (this.anchor === index) {
        /** 选框内的元素反选 */
        return {
          excludeRange: [-1, -1],
          includeRange: [...this.range],
          active: "current",
        };
      }
      const rangeStart = index < this.anchor ? index : this.range[0];
      const rangeEnd = index < this.anchor ? this.range[1] : index + 1;
      if (rangeStart === this.range[0] && rangeEnd === this.range[1]) {
        /** 锚点到目标（不包含目标）的元素反选 */
        return {
          excludeRange: [-1, -1],
          includeRange:
            index === rangeStart
              ? [rangeStart, this.anchor]
              : [this.anchor + 1, rangeEnd],
          active: "current",
        };
      }
      /** 缩小、扩大选框 */
      const ret: RangeInfo = {
        excludeRange:
          rangeStart > this.range[0]
            ? [this.range[0], rangeStart] // 起始值变大
            : rangeStart === this.range[0] && rangeEnd < this.range[1]
            ? [rangeEnd, this.range[1]] // 结束值变小
            : [-1, -1],
        includeRange: [rangeStart, rangeEnd],
        active: "anchor",
      };

      this.range = [rangeStart, rangeEnd];
      return ret;
    }
  }
  clear() {
    this.anchor = null;
    this.range = null;
  }
}
